package com.liuqi.openai.core.client.httpclient;

import com.liuqi.openai.core.chat.ChatCompletionRequest;
import com.liuqi.openai.core.chat.ChatCompletionResponse;
import com.liuqi.openai.core.client.AbstractOpenAiClient;
import com.liuqi.openai.core.client.Executor;
import com.liuqi.openai.core.completion.CompletionRequest;
import com.liuqi.openai.core.completion.CompletionResponse;
import com.liuqi.openai.core.embedding.EmbeddingRequest;
import com.liuqi.openai.core.embedding.EmbeddingResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.hc.client5.http.config.ConnectionConfig;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.core5.http.io.SocketConfig;
import org.apache.hc.core5.util.Timeout;

/**
 * httpclient5 openai api 调用执行器
 *
 * @author liuqi
 * @date 2025/7/18
 **/
@Slf4j
public class OpenAiHttpClient extends AbstractOpenAiClient {

    /**
     * http client
     */
    private final CloseableHttpClient httpClient;

    private OpenAiHttpClient(Builder serviceBuilder) {
        super(serviceBuilder.baseUrl,
                serviceBuilder.apiVersion,
                serviceBuilder.openAiApiKey,
                serviceBuilder.connectTimeout,
                serviceBuilder.readTimeout);

        log.info("create OpenAiClient, HttpClient5 implement. baseUrl[{}]", serviceBuilder.baseUrl);

        // 配置 httpclient
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
        connectionManager.setDefaultConnectionConfig(
                ConnectionConfig.custom()
                        .setConnectTimeout(Timeout.of(connectTimeout))
                        .setSocketTimeout(Timeout.of(readTimeout))
                        .build()
        );
        connectionManager.setDefaultSocketConfig(
                SocketConfig.custom()
                        .setSoKeepAlive(true)
                        .build()
        );
        connectionManager.setMaxTotal(100);
        connectionManager.setDefaultMaxPerRoute(20);

        log.info("init HttpClient5, ConnectTimeout[{}]秒, SocketTimeout[{}]秒, MaxTotal[{}], DefaultMaxPerRoute[{}]",
                connectTimeout.getSeconds(), readTimeout.getSeconds(), 100, 20);

        // 初始化 httpclient
        this.httpClient = HttpClients.custom()
                .setConnectionManager(connectionManager)
                // 添加httpclient拦截器, 在请求头中添加 apikey
                .addRequestInterceptorFirst((request, entity, context) -> {
                    request.addHeader("Authorization", "Bearer " + openAiApiKey);
                })
                .build();
    }

    public static Builder builder() {
        return new Builder();
    }

    public static class Builder extends AbstractOpenAiClient.Builder<OpenAiHttpClient, Builder> {
        public OpenAiHttpClient build() {
            return new OpenAiHttpClient(this);
        }
    }

    @Override
    public Executor<CompletionResponse> completion(CompletionRequest request) {
        return new HttpClientExecutor<>(
                this.httpClient,
                formatUrl("completions"),
                request.getStream(),
                () -> request,
                CompletionResponse.class
        );
    }

    @Override
    public Executor<ChatCompletionResponse> chatCompletion(ChatCompletionRequest request) {
        return new HttpClientExecutor<>(
                this.httpClient,
                formatUrl("chat/completions"),
                request.getStream(),
                () -> request,
                ChatCompletionResponse.class
        );
    }

    @Override
    public Executor<EmbeddingResponse> embedding(EmbeddingRequest request) {
        return new HttpClientExecutor<>(
                this.httpClient,
                formatUrl("embeddings"),
                () -> request,
                EmbeddingResponse.class
        );
    }

}
